package hnsw

import (
	"encoding/json"
	"fmt"
	"log"
	"slices"

	"github.com/tendermint/tendermint/my_app/querylayer/vindex/config"
)

type Hnsw_Index struct {
	hnsw        *Hnsw
	ownermap    map[uint32]string
	objectIDmap map[uint32]string
	obCondition map[string]bool
	ads         []*TreeNode
	truthADS    *TreeNode
	efSearch    int
	deletednum  int
}

type Hnsw_Proof struct {
	Enterpoint      int
	Vo_temp         []string
	Truth_VO        string
	Point_info      map[int][]int8
	True_point_info map[int]Point
	Grid_info       []map[int]Point
}

func New_Hnsw_Index(dimension int) *Hnsw_Index {
	var zero Point = make([]float32, dimension)
	hnsw := New(config.M, config.EfConstruction, zero)
	hnsw.Grow(config.Maxhnsw)
	hnsw.BuildADS()
	truthads, ads := hnsw.GetADS()

	return &Hnsw_Index{
		hnsw:        hnsw,
		efSearch:    config.EfSearch,
		truthADS:    truthads,
		ads:         ads,
		ownermap:    make(map[uint32]string),
		objectIDmap: make(map[uint32]string),
		obCondition: make(map[string]bool),
		deletednum:  0,
	}
}

func (index *Hnsw_Index) Insert(id int, object_id string, value []float32) error {
	// id, err := strconv.ParseUint(string(key), 10, 32)
	// if err != nil {
	// 	return nil
	// }
	// fmt.Printf("hnsw 插入向量\n")
	// fmt.Printf("hnsw key=%d objid=%s\n", id, object_id)
	index.hnsw.Add(value, uint32(id), true)
	index.objectIDmap[uint32(id)] = object_id
	index.obCondition[object_id] = true //===============
	//HNSW更新ads
	index.set_ADS()
	log.Println(index.hnsw.Stats())
	return nil
}

func (index *Hnsw_Index) set_ADS() error {
	index.truthADS, index.ads = index.hnsw.GetADS()
	return nil
}

// 返回相似肺炎图片去重后ownerID、proof
func (index *Hnsw_Index) Count_case_Search(query []float32) ([]string, Hnsw_Proof) {
	//执行查询
	resultSet, enterpoint, vo_temp, truth_VO, point_info, true_point_info, grid_info, _ := index.hnsw.Search(query, index.efSearch, 100, index.ads)

	// similarCase := index.filtercase(resultSet, bound)

	//提取向量id
	len := resultSet.Len()
	kids := make([]uint32, resultSet.Len())
	for i := len - 1; i >= 0; i-- {
		id := resultSet.Pop().ID
		kids[i] = id
	}
	//证明
	proof := Hnsw_Proof{
		Enterpoint:      enterpoint,
		Vo_temp:         vo_temp,
		Truth_VO:        truth_VO,
		Point_info:      point_info,
		True_point_info: true_point_info,
		Grid_info:       grid_info,
	}
	owerid := index.getUniqueStrings(kids)
	return owerid, proof
}

func (index *Hnsw_Index) Knn_Search(query []float32, K int) ([]string, [][]float32, []byte) {
	//K值根据已删除obj数量更改
	resultSet, enterpoint, vo_temp, truth_VO, point_info, true_point_info, grid_info, _ := index.hnsw.Search(query, index.efSearch, K+index.deletednum+1, index.ads)
	proof := Hnsw_Proof{
		Enterpoint:      enterpoint,
		Vo_temp:         vo_temp,
		Truth_VO:        truth_VO,
		Point_info:      point_info,
		True_point_info: true_point_info,
		Grid_info:       grid_info,
	}

	//考虑proof用什么方式序列化反序列化
	proofjson, err := json.Marshal(proof)
	if err != nil {
		fmt.Printf("error")
	}

	//提取向量id
	//fmt.Printf("result len=%d\n", resultSet.Len())
	kobjID := make([]string, K)
	results := make([][]float32, K)
	i := K - 1
	for {
		if i == -1 {
			break
		}
		if resultSet.Len() == 0 {
			break
		}
		//fmt.Printf("i=%d\n", i)
		r := resultSet.Pop()
		id := r.ID
		objid := index.objectIDmap[id]
		//fmt.Printf("%d,objid=%s ", id, objid)
		//删除
		if index.isdeleted(objid) {
			continue
		} else {
			kobjID[i] = objid
			results = append(results, index.hnsw.nodes[id].p)
			i--
		}
	}
	slices.Reverse(results)
	return kobjID, results, proofjson
}

func (index *Hnsw_Index) Verification(query []float32, proof Hnsw_Proof) error {
	// fmt.Printf("验证结果-")
	enterpoint := proof.Enterpoint
	vo_temp := proof.Vo_temp
	truth_VO := proof.Truth_VO
	point_info := proof.Point_info
	true_point_info := proof.True_point_info
	grid_info := proof.Grid_info

	err := index.hnsw.verification(enterpoint, vo_temp, truth_VO, point_info, true_point_info, grid_info, index.truthADS, index.ads, query, index.efSearch)
	return err
}

func (index *Hnsw_Index) getUniqueStrings(keys []uint32) []string {
	// 使用map来跟踪已经遇到的字符串
	seen := make(map[string]bool)
	var result []string

	// 遍历每个key
	for _, key := range keys {
		// 检查key是否在ownermap中
		if value, exists := index.ownermap[key]; exists {
			// 如果字符串未被见过，则添加到结果切片中
			if !seen[value] {
				seen[value] = true
				result = append(result, value)
			}
		}
	}

	return result
}

func (index *Hnsw_Index) Delete(objectid string) error {
	fmt.Println("index delete object:", objectid)
	_, exists := index.obCondition[objectid]
	if !exists {
		return fmt.Errorf("object dosen't exist")
	} else {
		index.obCondition[objectid] = false
	}
	index.deletednum++
	fmt.Printf("deleting objid=%s \n", objectid)
	return nil
}

func (index *Hnsw_Index) isdeleted(objid string) bool {
	if index.obCondition[objid] {
		return false
	} else {
		return true
	}
}
